#include <curl.h>
#include <assert.h>
#include "BotBasic.h"

#define BOT_MAX_REDIRECTS   10L
#define BOT_TIMEOUT         20

CBotBasic::CBotBasic()
{
    memset(&m_CurlVec, 0, sizeof(CURL_VECTOR));
    Initialize();
}

CBotBasic::~CBotBasic()
{
    UnInitialize();
}

void CBotBasic::Initialize()
{
    m_Curl = curl_easy_init();
    if (m_Curl)
    {
        curl_easy_setopt(m_Curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(m_Curl, CURLOPT_MAXREDIRS, BOT_MAX_REDIRECTS);
        curl_easy_setopt(m_Curl, CURLOPT_FAILONERROR, 1L);
        curl_easy_setopt(m_Curl, CURLOPT_TIMEOUT, BOT_TIMEOUT);
        curl_easy_setopt(m_Curl, CURLOPT_COOKIESESSION, 1L);
        curl_easy_setopt(m_Curl, CURLOPT_COOKIEFILE, "");
        curl_easy_setopt(m_Curl, CURLOPT_WRITEDATA, this);
        curl_easy_setopt(m_Curl, CURLOPT_WRITEFUNCTION, &CBotBasic::Handle);
    }

    //std::string r;
    //SendGetRequest("http://oldbk.com", r);
    //SendGetRequest("http://oldbk.com", r);
    return;
}

void CBotBasic::UnInitialize()
{
    if (m_Curl)
        curl_easy_cleanup(m_Curl);
}

size_t CBotBasic::Handle(char *data, size_t size, size_t nmemb, void * p)
{
    return ((CBotBasic *)p)->HandleImpl(data, size, nmemb);
}

size_t CBotBasic::HandleImpl(char *ptr, size_t size, size_t nmemb)
{
    if (size * nmemb == 0)
        return 0;

    if (m_CurlVec.Size + size * nmemb > m_CurlVec.Allocated)
    {
        char *new_data = (char *)realloc(m_CurlVec.Data, m_CurlVec.Size + size * nmemb);
        if (!new_data)
            return 0;
        m_CurlVec.Data = new_data;
        m_CurlVec.Allocated = m_CurlVec.Size + size * nmemb;
    }

    memcpy(m_CurlVec.Data + m_CurlVec.Size, ptr, size * nmemb);
    m_CurlVec.Size += size * nmemb;

    return size * nmemb;
}

void CBotBasic::FreeCurlVector(PCURL_VECTOR Vec)
{
    if (Vec->Data)
    {
        free(Vec->Data);
        Vec->Data = NULL;
    }

    Vec->Allocated = 0;
    Vec->Size = 0;
}

bool CBotBasic::GetRequest(const char *Url, std::string &Result)
{
    assert(Url);
    
    curl_easy_setopt(m_Curl, CURLOPT_HTTPGET, 1L);
    curl_easy_setopt(m_Curl, CURLOPT_URL, Url);

    FreeCurlVector(&m_CurlVec);

    if (curl_easy_perform(m_Curl))
        return false;

    Result = m_CurlVec.Data;
    return true;
}

bool CBotBasic::PostRequest(const char *Url, std::string &PostFields, std::string &Result)
{
    assert(Url);

    curl_easy_setopt(m_Curl, CURLOPT_POST, 1L);
    curl_easy_setopt(m_Curl, CURLOPT_URL, Url);
    curl_easy_setopt(m_Curl, CURLOPT_POSTFIELDS, PostFields.c_str());

    FreeCurlVector(&m_CurlVec);

    if (curl_easy_perform(m_Curl))
        return false;

    Result = m_CurlVec.Data;
    return true;
}

bool CBotBasic::GetBinaryData(const char *Url, const char **Data, size_t &Size)
{
    assert(Url);
    assert(Data);
    
    curl_easy_setopt(m_Curl, CURLOPT_HTTPGET, 1L);
    curl_easy_setopt(m_Curl, CURLOPT_URL, Url);

    FreeCurlVector(&m_CurlVec);

    if (curl_easy_perform(m_Curl))
        return false;

    *Data = m_CurlVec.Data;
    Size = m_CurlVec.Size;
    return true;
}

bool CBotBasic::SendGetRequest(const char *Url, std::string &Result)
{
    for (int ii = 0; ii < BOT_REPEAT_COUNT; ++ii)
    {
	    if (GetRequest(Url, Result))
            return true;
    }

    return false;
}

bool CBotBasic::SendPostRequest(const char *Url, std::string &PostFields, std::string &Result)
{
	for (int ii = 0; ii < BOT_REPEAT_COUNT; ++ii)
    {
		if (PostRequest(Url, PostFields, Result))
			return true;
	}

    return false;
}